1//////////////////////////////////////////////////////////////////////
   2// LibFile: threading.scad
   3//   Provides generic threading support and specialized support for standard triangular (UTS/ISO) threading,
   4//   trapezoidal threading (ACME), pipe threading, buttress threading, square threading and ball screws.  
   5// Includes:
   6//   include <BOSL2/std.scad>
   7//   include <BOSL2/threading.scad>
   8// FileGroup: Threaded Parts
   9// FileSummary: Various types of threaded rods and nuts.
  10//////////////////////////////////////////////////////////////////////
  11
  12
  13// Section: Thread Ends and Options
  14//   A standard process for making machine screws is to begin with round stock that has
  15//   beveled ends.  This stock is then rolled between flat, grooved plates to form the threads.
  16//   The result is a bolt that looks like this at the end:
  17// Figure(3D,Med,NoAxes,VPR=[83.7,0,115.5],VPT=[1.37344,1.26411,-0.299415],VPD=35.5861): 
  18//   threaded_rod(d=13,pitch=2,l=10,blunt_start=false,$fn=80);
  19// Figure(2D,Med,NoAxes): A properly mated screw and bolt with beveled ends
  20//   $fn=32;
  21//   projection(cut=true)
  22//   xrot(-90){
  23//   down(2.5)difference(){
  24//     cuboid([20,20,5]);
  25//     zrot(20)
  26//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
  27//   }
  28//   up(2.85-2)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
  29//   
  30//   }
  31// Continues:
  32//   Cross threading occurs when the bolt is misaligned with the threads in the nut.
  33//   It can destroy the threads, or cause the nut to jam.  The standard beveled end process
  34//   makes cross threading a possibility because the beveled partial threads can pass
  35//   each other when the screw enters the nut.
  36// Figure(2D,Med,NoAxes):
  37//   $fn=32;
  38//   projection(cut=true)
  39//   xrot(-90){
  40//   down(2.5)difference(){
  41//     cuboid([20,20,5]);
  42//     zrot(20)
  43//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
  44//   }
  45//   left(.6)up(2.99)yrot(-atan(2/13)-1)rot(180+30)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
  46//   }
  47// Continues:
  48//   In addition, those partial screw threads may be weak, and easily broken.  They do
  49//   not contribute to the strength of the assembly.  
  50//   In 1891 Clinton A. Higbee received a patent for a modification to screw threads
  51//   https://patents.google.com/patent/US447775A meant to address these limitations.
  52//   Instead of beveling the end of the screw, Higbee said to remove the partial thread.
  53//   The resulting screw might look like this:
  54// Figure(3D,Med,NoAxes,VPR=[72,0,294],VPT=[0,0,0],VPD=44):
  55//   $fn=48;
  56//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,lead_in_shape="cut",end_len=.2);
  57// Continues:
  58//   Because the threads are complete everywhere, cross threading is unlikely to occur.
  59//   This type of threading has been called "Higbee threads", but in recent machinist
  60//   handbooks it is called "blunt start" threading.  
  61//   This style of thread is not commonly used in metal fasteners because it requires
  62//   machining the threads, which is much more costly than the rolling procedure described
  63//   above.  However, plastic threads usually have some sort of gradual thread end.
  64//   For models that will be 3D printed, there is no reason to choose the standard
  65//   bevel end bolt, so in this library the blunt start threads are the default.
  66//   If you need standard bevel-end threads, you can choose them with the `blunt_start` options.
  67//   Note that blunt start threads are more efficient.
  68//   .
  69//   Various options exist for controlling the ends of threads. You can specify bevels on threaded rods.
  70//   In conventional threading, bevels are needed on the ends to remove sharp, thin edges, and
  71//   the bevel is sized to the full outer diameter of the threaded rod.  
  72//   With blunt start threading, the bevel appears on the unthreaded part of the rod.
  73//   On a threaded rod, a bevel value of `true` or a positive bevel value cut off the corner.
  74// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44):
  75//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=true,$fn=80);
  76// Continues:
  77//   A negative bevel value produces a flaring bevel, that might be useful if the rod needs to mate with another part.
  78//   You can also set `bevel="reverse"` to get a flaring bevel of the default size.
  79// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44): Negative bevel on a regular threaded rod.
  80//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=-2,$fn=80);
  81// Continues:
  82//   If you set `internal=true` to create a mask for a threaded hole, then bevels are reversed: positive bevels flare outward so that when you subtract
  83//   the threaded rod it gives a beveled edge to the hole.  In this case, negative bevels go inward, which might be useful to
  84//   create a bevel at the bottom of a threaded hole.
  85// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44): Threaded rod mask produced using `internal=true` with regular bevel at the top and reversed bevel at the bottom.  
  86//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel2=true,bevel1="reverse",internal=true,$fn=80);
  87// Continues:
  88//   You can also extend the unthreaded section using the `end_len` parameters.  A long unthreaded section will make
  89//   it impossible to tilt the bolt and produce misaligned threads, so it could make assembly easier.  
  90// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=48): Negative bevel on a regular threaded rod.
  91//   threaded_rod(d=13,pitch=2,l=15,end_len2=5,blunt_start=true,bevel=true,$fn=80);
  92// Continues:
  93//   It is also possible to adjust the length of the lead-in section of threads, or the
  94//   shape of that lead-in section.  The lead-in length can be set using the `lead_in` arguments
  95//   to specify a length or the `lead_in_ang` arguments to specify an angle.  For general
  96//   threading applications, making the lead in long creates a smaller thread that could
  97//   be more fragile and more prone to cross threading.  
  98// Figure(3D,Med,NoAxes,VPR=[52,0,300],VPT=[0,0,4],VPD=35.5861):
  99//   threaded_rod(d=13,pitch=2,l=10,lead_in=6,blunt_start=true,bevel=false,$fn=80);
 100// Continues:
 101//   To change the form of the thread end you use the `lead_in_shape` argument.
 102//   You can specify "sqrt", "cut" or "smooth" shapes.  The "sqrt" shape is the historical
 103//   shape used in the library.  The "cut" shape is available to model Higbee pattern threads, but
 104//   is not as good as the others in practice, because the flat faces on the threads can hit each other.
 105//   The lead-in shape is produced by applying a scale factor to the thread cross section that varies along the lead-in length. 
 106//   You can also specify a custom shape
 107//   by giving a function literal, `f(x,L)` where `L` will be the total linear
 108//   length of the lead-in section and `x` will be a value between 0 and 1 giving
 109//   the position in the lead in, with 0 being the tip and 1 being the full height thread.
 110//   The return value must be a 2-vector giving the thread width scale and thread height
 111//   scale at that location.  If `x<0` the function must return a thread height scale
 112//   of zero, but it is usually best if the thread width scale does not go to zero,
 113//   because that will give a sharply pointed thread end.  If `x>1` the function must
 114//   return `[1,1]`.  
 115// Figure(3D,Med,NoAxes,VPR=[75,0,338],VPT=[-2,0,3.3],VPD=25): The standard lead in shapes
 116//   left_half()zrot(0){
 117//   up(2)   threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,anchor=BOT);
 118//   up(4)   threaded_rod(d=13,pitch=2,l=2.5,blunt_start=true,bevel=false,$fn=128,lead_in_shape="cut",end_len2=.5,anchor=BOT);
 119//      threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,lead_in_shape="smooth",anchor=BOT);
 120//   }
 121//   $fn=64;
 122//   s=.85;
 123//   color("black")
 124//   up(3.5)left(4.5)fwd(6)rot($vpr){
 125//      back(1.9)text3d("cut",size=s);
 126//      text3d("sqrt",size=s);
 127//      fwd(1.9)text3d("smooth",size=s);
 128//   }   
 129
 130
 131// Section: Standard (UTS/ISO) Threading
 132
 133// Module: threaded_rod()
 134// Synopsis: Creates an UTS/ISO triangular threaded rod.
 135// SynTags: Geom
 136// Topics: Threading, Screws
 137// See Also: threaded_nut()
 138// Usage:
 139//   threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
 140// Description:
 141//   Constructs a standard ISO (metric) or UTS (English) threaded rod.  These threads are close to triangular,
 142//   with a 60 degree thread angle.  You can give diameter value which specifies the outer diameter and will produce
 143//   the "basic form" or you can
 144//   set d to a triplet [d_min, d_pitch, d_major] where are parameters determined by the ISO and UTS specifications
 145//   that define clearance sizing for the threading.  See screws.scad for how to make screws
 146//   using the specification parameters.  
 147// Arguments:
 148//   d = Outer diameter of threaded rod, or a triplet of [d_min, d_pitch, d_major]. 
 149//   l / length / h / height = length of threaded rod.
 150//   pitch = Length between threads.
 151//   ---
 152//   left_handed = if true, create left-handed threads.  Default = false
 153//   starts = The number of lead starts.  Default: 1
 154//   bevel = if true, bevel the thread ends.  Default: false
 155//   bevel1 = if true bevel the bottom end.
 156//   bevel2 = if true bevel the top end.
 157//   internal = If true, make this a mask for making internal threads.
 158//   d1 = Bottom outside diameter of threads.
 159//   d2 = Top outside diameter of threads.
 160//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 161//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 162//   blunt_start2 = If true apply truncated blunt start threads top end.
 163//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 164//   end_len1 = Specify unthreaded length at the bottom
 165//   end_len2 = Specify unthreaded length at the top
 166//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 167//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 168//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 169//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 170//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 171//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 172//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 173//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop. Default: false
 174//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 175//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 176//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 177//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 178// Example(2D):
 179//   projection(cut=true)
 180//       threaded_rod(d=10, l=15, pitch=1.5, orient=BACK);
 181// Examples(Med):
 182//   threaded_rod(d=25, height=20, pitch=2, $fa=1, $fs=1);
 183//   threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
 184//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, end_len=1.5, bevel=true);
 185//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, blunt_start=false);
 186// Example(Med;VPR=[100,0,5];VPD=220): Masking a Horizontal Threaded Hole
 187//   difference() {
 188//     cuboid(50);
 189//     threaded_rod(
 190//         d=25, l=51, pitch=4, $fn=36,
 191//         internal=true, bevel=true,
 192//         blunt_start=false,
 193//         teardrop=true, orient=FWD
 194//     );
 195//   }
 196// Example(Big,NoAxes): Diamond threading where both left-handed and right-handed nuts travel (in the same direction) on the threaded rod:
 197//   $fn=32;
 198//   $slop = 0.075;
 199//   d = 3/8*INCH;
 200//   pitch = 1/16*INCH;
 201//   starts=3;
 202//   xdistribute(19){
 203//       intersection(){
 204//         threaded_rod(l=40, pitch=pitch, d=d,starts=starts,anchor=BOTTOM,end_len=.44);
 205//         threaded_rod(l=40, pitch=pitch, d=d, left_handed=true,starts=starts,anchor=BOTTOM);
 206//       }
 207//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,anchor=BOTTOM);
 208//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,left_handed=true,anchor=BOTTOM);
 209//   }
 210function threaded_rod(
 211    d, l, pitch,
 212    left_handed=false,
 213    bevel,bevel1,bevel2,starts=1,
 214    internal=false,
 215    d1, d2, length, h, height,
 216    blunt_start, blunt_start1, blunt_start2,
 217    lead_in, lead_in1, lead_in2,
 218    lead_in_ang, lead_in_ang1, lead_in_ang2,
 219    end_len, end_len1, end_len2,
 220    lead_in_shape="default",
 221    teardrop=false,
 222    anchor, spin, orient
 223) = no_function("threaded_rod");
 224
 225module threaded_rod(
 226    d, l, pitch,
 227    left_handed=false,
 228    bevel,bevel1,bevel2,starts=1,
 229    internal=false,
 230    d1, d2, length, h, height,
 231    blunt_start, blunt_start1, blunt_start2,
 232    lead_in, lead_in1, lead_in2,
 233    lead_in_ang, lead_in_ang1, lead_in_ang2,
 234    end_len, end_len1, end_len2,
 235    lead_in_shape="default",
 236    teardrop=false,
 237    anchor, spin, orient
 238) {
 239    dummy1=
 240      assert(all_positive(pitch))
 241      assert(all_positive(d) || (is_undef(d) && all_positive([d1,d2])));
 242    basic = is_num(d) || is_undef(d) || is_def(d1) || is_def(d2);
 243    dummy2 = assert(basic || is_vector(d,3));
 244    depth = basic ? cos(30) * 5/8
 245                  : (d[2] - d[0])/2/pitch;
 246    crestwidth = basic ? 1/8 : 1/2 - (d[2]-d[1])/sqrt(3)/pitch;
 247    profile =    [
 248                  [-depth/sqrt(3)-crestwidth/2, -depth],
 249                  [              -crestwidth/2,      0],
 250                  [               crestwidth/2,      0],
 251                  [ depth/sqrt(3)+crestwidth/2, -depth]
 252                 ];
 253    oprofile = internal? [
 254        [-6/16, -depth],
 255        [-1/16,  0],
 256        [-1/32,  0.02],
 257        [ 1/32,  0.02],
 258        [ 1/16,  0],
 259        [ 6/16, -depth]
 260    ] : [
 261        [-7/16, -depth*1.07],
 262        [-6/16, -depth],
 263        [-1/16,  0],
 264        [ 1/16,  0],
 265        [ 6/16, -depth],
 266        [ 7/16, -depth*1.07]
 267    ];
 268    generic_threaded_rod(
 269        d=basic ? d : d[2], d1=d1, d2=d2, l=l,
 270        pitch=pitch,
 271        profile=profile,starts=starts,
 272        left_handed=left_handed,
 273        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 274        internal=internal, length=length, height=height, h=h,
 275        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 276        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 277        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 278        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 279        teardrop=teardrop,
 280        anchor=anchor,
 281        spin=spin,
 282        orient=orient
 283    ) children();
 284}
 285
 286
 287
 288// Module: threaded_nut()
 289// Synopsis: Creates an UTS/ISO triangular threaded nut.
 290// SynTags: Geom
 291// Topics: Threading, Screws
 292// See Also: threaded_rod()
 293// Usage:
 294//   threaded_nut(nutwidth, id, h|height|thickness, pitch,...) [ATTACHMENTS];
 295// Description:
 296//   Constructs a hex nut or square nut for an ISO (metric) or UTS (English) threaded rod.
 297//   The inner diameter is measured from the bottom of the threads.  
 298// Arguments:
 299//   nutwidth = flat to flat width of nut
 300//   id = inner diameter of threaded hole, measured from bottom of threads
 301//   h / height / l / length / thickness = height/thickness of nut.
 302//   pitch = Distance between threads, or zero for no threads. 
 303//   ---
 304//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 305//   left_handed = if true, create left-handed threads.  Default = false
 306//   starts = The number of lead starts.  Default: 1
 307//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 308//   bevel1 = if true, bevel the outside of the nut bottom.
 309//   bevel2 = if true, bevel the outside of the nut top. 
 310//   bevang = set the angle for the outside nut bevel.  Default: 30
 311//   ibevel = if true, bevel the inside (the hole).   Default: true
 312//   ibevel1 = if true bevel the inside, bottom end.
 313//   ibevel2 = if true bevel the inside, top end.
 314//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 315//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 316//   blunt_start2 = If true apply truncated blunt start threads top end.
 317//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 318//   end_len1 = Specify unthreaded length at the bottom
 319//   end_len2 = Specify unthreaded length at the top
 320//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 321//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 322//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 323//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 324//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 325//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 326//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 327//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 328//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 329//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 330//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 331// Examples(Med):
 332//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.05, $fa=1, $fs=1);
 333//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, bevel=false, $slop=0.1, $fa=1, $fs=1);
 334//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.1, $fa=1, $fs=1);
 335//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, bevel2=true, $slop=0.1, $fa=1, $fs=1);
 336//   rot(90)threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25,blunt_start=false, $slop=0.1, $fa=1, $fs=1);
 337function threaded_nut(
 338    nutwidth, id, h,
 339    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
 340    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
 341    length, l,
 342    blunt_start, blunt_start1, blunt_start2,
 343    lead_in, lead_in1, lead_in2,
 344    lead_in_ang, lead_in_ang1, lead_in_ang2,
 345    end_len, end_len1, end_len2,
 346    lead_in_shape="default",
 347    anchor, spin, orient
 348)=no_function("threaded_nut");
 349module threaded_nut(
 350    nutwidth, id, h,
 351    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
 352    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
 353    length, l,
 354    blunt_start, blunt_start1, blunt_start2,
 355    lead_in, lead_in1, lead_in2,
 356    lead_in_ang, lead_in_ang1, lead_in_ang2,
 357    end_len, end_len1, end_len2,
 358    lead_in_shape="default",
 359    anchor, spin, orient
 360) {
 361    dummy1=
 362          assert(all_nonnegative(pitch), "Nut pitch must be nonnegative")
 363          assert(all_positive(id), "Nut inner diameter must be positive")
 364          assert(all_positive(h),"Nut thickness must be positive");
 365    basic = is_num(id) || is_undef(id) || is_def(id1) || is_def(id2);
 366    dummy2 = assert(basic || is_vector(id,3));
 367    depth = basic ? cos(30) * 5/8
 368                  : (id[2] - id[0])/2/pitch;
 369    crestwidth = basic ? 1/8 : 1/2 - (id[2]-id[1])/sqrt(3)/pitch;
 370    profile =    [
 371                  [-depth/sqrt(3)-crestwidth/2, -depth],
 372                  [              -crestwidth/2,      0],
 373                  [               crestwidth/2,      0],
 374                  [ depth/sqrt(3)+crestwidth/2, -depth]
 375                 ];
 376    oprofile = [
 377        [-6/16, -depth/pitch],
 378        [-1/16,  0],
 379        [-1/32,  0.02],
 380        [ 1/32,  0.02],
 381        [ 1/16,  0],
 382        [ 6/16, -depth/pitch]
 383    ];
 384    generic_threaded_nut(
 385        nutwidth=nutwidth,
 386        id=basic ? id : id[2], id1=id1, id2=id2,
 387        h=h,
 388        pitch=pitch,
 389        profile=profile,starts=starts,shape=shape, 
 390        left_handed=left_handed,
 391        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 392        ibevel1=ibevel1, ibevel2=ibevel2, ibevel=ibevel,
 393        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 394        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 395        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 396        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 397        l=l,length=length,
 398        anchor=anchor, spin=spin,
 399        orient=orient
 400    ) children();
 401}
 402
 403// Section: Trapezoidal Threading
 404
 405
 406// Module: trapezoidal_threaded_rod()
 407// Synopsis: Creates a trapezoidal threaded rod.
 408// SynTags: Geom
 409// Topics: Threading, Screws
 410// See Also: trapezoidal_threaded_nut()
 411// Usage:
 412//   trapezoidal_threaded_rod(d, l|length, pitch, [thread_angle=|flank_angle=], [thread_depth=], [internal=], ...) [ATTACHMENTS];
 413// Description:
 414//   Constructs a threaded rod with a symmetric trapezoidal thread.  Trapezoidal threads are used for lead screws because
 415//   they are one of the strongest symmetric profiles.  This tooth shape is stronger than a similarly
 416//   sized square thread becuase of its wider base.  However, it does place a radial load on the nut, unlike the square thread.
 417//   For loads in only one direction the asymmetric buttress thread profile can bear greater loads.  
 418//   .
 419//   By default produces the nominal dimensions
 420//   for metric trapezoidal threads: a thread angle of 30 degrees and a depth set to half the pitch.
 421//   You can also specify your own trapezoid parameters.  For ACME threads see acme_threaded_rod().
 422// Figure(2D,Med,NoAxes):
 423//   pa_delta = tan(15)/4;
 424//   rr1 = -1/2;
 425//   z1 = 1/4-pa_delta;
 426//   z2 = 1/4+pa_delta;
 427//   profile = [
 428//               [-z2, rr1],
 429//               [-z1,  0],
 430//               [ z1,  0],
 431//               [ z2, rr1],
 432//             ];
 433//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
 434//   stroke(fullprofile,width=1);
 435//   dir = fullprofile[2]-fullprofile[3];
 436//   dir2 = fullprofile[5]-fullprofile[4];
 437//   curve = arc(32,angle=[75,105],r=67.5);
 438//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
 439//   color("red"){
 440//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
 441//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
 442//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
 443//    back(10)text("thread",size=4,halign="center");
 444//    back(3)text("angle",size=4,halign="center");
 445//   }
 446// Figure(2D,Med,NoAxes):
 447//   pa_delta = tan(15)/4;
 448//      rr1 = -1/2;
 449//      z1 = 1/4-pa_delta;
 450//      z2 = 1/4+pa_delta;
 451//      profile = [
 452//                  [-z2, rr1],
 453//                  [-z1,  0],
 454//                  [ z1,  0],
 455//                  [ z2, rr1],
 456//                ];
 457//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
 458//      stroke(fullprofile,width=1);
 459//      dir = fullprofile[2]-fullprofile[3];
 460//      dir2 = fullprofile[5]-fullprofile[4];
 461//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
 462//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
 463//      color("red"){
 464//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
 465//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
 466//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
 467//       right(14)back(19)text("flank",size=4,halign="center");
 468//       right(14)back(14)text("angle",size=4,halign="center");
 469//      }
 470// Arguments:
 471//   d = Outer diameter of threaded rod.
 472//   l / length / h / height = Length of threaded rod.
 473//   pitch = Thread spacing. 
 474//   ---
 475//   thread_angle = Angle between two thread faces.  Default: 30
 476//   thread_depth = Depth of threads.  Default: pitch/2
 477//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
 478//   left_handed = If true, create left-handed threads.  Default: false
 479//   starts = The number of lead starts.  Default: 1
 480//   bevel = if true, bevel the thread ends.  Default: false
 481//   bevel1 = if true bevel the bottom end.
 482//   bevel2 = if true bevel the top end. 
 483//   internal = If true, make this a mask for making internal threads.  Default: false
 484//   d1 = Bottom outside diameter of threads.
 485//   d2 = Top outside diameter of threads.
 486//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 487//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 488//   blunt_start2 = If true apply truncated blunt start threads top end.
 489//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 490//   end_len1 = Specify unthreaded length at the bottom
 491//   end_len2 = Specify unthreaded length at the top
 492//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 493//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 494//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 495//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 496//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 497//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 498//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 499//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop. Default: false
 500//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 501//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 502//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 503//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 504// Example(2D):
 505//   projection(cut=true)
 506//       trapezoidal_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
 507// Examples(Med): 
 508//   trapezoidal_threaded_rod(d=10, l=40, pitch=2, $fn=32);  // Standard metric threading
 509//   rot(-65)trapezoidal_threaded_rod(d=10, l=17, pitch=2, blunt_start=false, $fn=32);  // Standard metric threading
 510//   trapezoidal_threaded_rod(d=10, l=17, pitch=2, bevel=true, $fn=32);  // Standard metric threading
 511//   trapezoidal_threaded_rod(d=10, h=30, pitch=2, left_handed=true, $fa=1, $fs=1);  // Standard metric threading
 512//   trapezoidal_threaded_rod(d=10, l=40, pitch=3, left_handed=true, starts=3, $fn=36);
 513//   trapezoidal_threaded_rod(l=25, d=10, pitch=2, starts=3, $fa=1, $fs=1, bevel=true, orient=RIGHT, anchor=BOTTOM);
 514//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, blunt_start=false, $fa=2, $fs=2);
 515//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, end_len=0, $fa=2, $fs=2);   
 516//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, left_handed=true, starts=4, $fa=2, $fs=2,end_len=0);
 517//   trapezoidal_threaded_rod(d=16, l=40, pitch=2, thread_angle=60);
 518//   trapezoidal_threaded_rod(d=25, l=40, pitch=10, thread_depth=8/3, thread_angle=100, starts=4, anchor=BOT, $fa=2, $fs=2,end_len=-2);
 519//   trapezoidal_threaded_rod(d=50, l=35, pitch=8, thread_angle=60, starts=11, lead_in=3, $fn=120);
 520//   trapezoidal_threaded_rod(d=10, l=40, end_len2=10, pitch=2, $fn=32);  // Unthreaded top end section
 521// Example(Med): Using as a Mask to Make Internal Threads
 522//   bottom_half() difference() {
 523//       cube(50, center=true);
 524//       trapezoidal_threaded_rod(d=40, l=51, pitch=5, thread_angle=30, internal=true, bevel=true, orient=RIGHT, $fn=36);
 525//   }
 526// Example(Med;VPR=[100,0,5];VPD=220): Masking a Horizontal Threaded Hole
 527//   difference() {
 528//     cuboid(50);
 529//     trapezoidal_threaded_rod(
 530//         d=25, l=51, pitch=4, $fn=36,
 531//         thread_angle=30,
 532//         internal=true, bevel=true,
 533//         blunt_start=false,
 534//         teardrop=true, orient=FWD
 535//     );
 536//   }
 537function trapezoidal_threaded_rod(
 538    d, l, pitch,
 539    thread_angle,
 540    thread_depth,
 541    flank_angle,
 542    left_handed=false,
 543    bevel,bevel1,bevel2,
 544    starts=1, 
 545    internal=false,
 546    d1, d2, length, h, height,
 547    blunt_start, blunt_start1, blunt_start2,
 548    lead_in, lead_in1, lead_in2,
 549    lead_in_ang, lead_in_ang1, lead_in_ang2,
 550    end_len, end_len1, end_len2,
 551    lead_in_shape="default",
 552    teardrop=false,
 553    anchor, spin, orient
 554) = no_function("trapezoidal_threaded_rod");
 555module trapezoidal_threaded_rod(
 556    d, l, pitch,
 557    thread_angle,
 558    thread_depth,
 559    flank_angle,
 560    left_handed=false,
 561    bevel,bevel1,bevel2,
 562    starts=1, 
 563    internal=false,
 564    d1, d2, length, h, height,
 565    blunt_start, blunt_start1, blunt_start2,
 566    lead_in, lead_in1, lead_in2,
 567    lead_in_ang, lead_in_ang1, lead_in_ang2,
 568    end_len, end_len1, end_len2,
 569    lead_in_shape="default",
 570    teardrop=false,
 571    anchor, spin, orient
 572) {
 573    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
 574    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
 575    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
 576             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
 577             assert(thread_angle<=90 || all_positive([thread_depth]),
 578                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
 579    depth = first_defined([thread_depth,pitch/2]);
 580    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
 581    dummy2 = assert(pa_delta<=1/4, "Specified thread geometry is impossible");
 582    rr1 = -depth/pitch;
 583    z1 = 1/4-pa_delta;
 584    z2 = 1/4+pa_delta;
 585    profile = [
 586               [-z2, rr1],
 587               [-z1,  0],
 588               [ z1,  0],
 589               [ z2, rr1],
 590              ];
 591    generic_threaded_rod(d=d,l=l,pitch=pitch,profile=profile,
 592                         left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,d1=d1,d2=d2,
 593                         internal=internal, length=length, height=height, h=h,
 594                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 595                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 596                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 597                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 598                         teardrop=teardrop, anchor=anchor,spin=spin,orient=orient)
 599      children();
 600}
 601
 602
 603// Module: trapezoidal_threaded_nut()
 604// Synopsis: Creates a trapezoidal threaded nut.
 605// SynTags: Geom
 606// Topics: Threading, Screws
 607// See Also: trapezoidal_threaded_rod()
 608// Usage:
 609//   trapezoidal_threaded_nut(nutwidth, id, h|height|thickness, pitch, [thread_angle=|flank_angle=], [thread_depth], ...) [ATTACHMENTS];
 610// Description:
 611//   Constructs a hex nut or square nut for a symmetric trapzoidal threaded rod.  By default produces
 612//   the nominal dimensions for metric trapezoidal threads: a thread angle of 30 degrees and a depth
 613//   set to half the pitch.  You can also specify your own trapezoid parameters.  For ACME threads see
 614//   acme_threaded_nut().
 615// Arguments:
 616//   nutwidth = flat to flat width of nut
 617//   id = inner diameter of threaded hole, measured from bottom of threads
 618//   h / height / l / length / thickness = height/thickness of nut.
 619//   pitch = Thread spacing.
 620//   ---
 621//   thread_angle = Angle between two thread faces.  Default: 30
 622//   thread_depth = Depth of the threads.  Default: pitch/2
 623//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
 624//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 625//   left_handed = if true, create left-handed threads.  Default = false
 626//   starts = The number of lead starts.  Default = 1
 627//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 628//   bevel1 = if true, bevel the outside of the nut bottom.
 629//   bevel2 = if true, bevel the outside of the nut top. 
 630//   bevang = set the angle for the outside nut bevel.  Default: 30
 631//   ibevel = if true, bevel the inside (the hole).   Default: true
 632//   ibevel1 = if true bevel the inside, bottom end.
 633//   ibevel2 = if true bevel the inside, top end.
 634//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 635//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 636//   blunt_start2 = If true apply truncated blunt start threads top end.
 637//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 638//   end_len1 = Specify unthreaded length at the bottom
 639//   end_len2 = Specify unthreaded length at the top
 640//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 641//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 642//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 643//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 644//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 645//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 646//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 647//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 648//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 649//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 650//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 651// Examples(Med):
 652//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, $slop=0.1, anchor=UP);
 653//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, bevel=false, $slop=0.05, anchor=UP);
 654//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, $slop=0.1, left_handed=true);
 655//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15);
 656//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15, blunt_start=false);
 657//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=0, $slop=0.2);   // No threads
 658function trapezoidal_threaded_nut(
 659    nutwidth,
 660    id,
 661    h,
 662    pitch,
 663    thread_angle,
 664    thread_depth, shape="hex",
 665    flank_angle,
 666    left_handed=false,
 667    starts=1,
 668    bevel,bevel1,bevel2,bevang=30,
 669    ibevel1,ibevel2,ibevel,
 670    thickness,height,
 671    id1,id2,
 672    length, l,
 673    blunt_start, blunt_start1, blunt_start2,
 674    lead_in, lead_in1, lead_in2,
 675    lead_in_ang, lead_in_ang1, lead_in_ang2,
 676    end_len, end_len1, end_len2,
 677    lead_in_shape="default",
 678    anchor, spin, orient
 679) = no_function("trapezoidal_threaded_nut");
 680module trapezoidal_threaded_nut(
 681    nutwidth,
 682    id,
 683    h,
 684    pitch,
 685    thread_angle,
 686    thread_depth, shape="hex",
 687    flank_angle,
 688    left_handed=false,
 689    starts=1,
 690    bevel,bevel1,bevel2,bevang=30,
 691    ibevel1,ibevel2,ibevel,
 692    thickness,height,
 693    id1,id2,
 694    length, l,
 695    blunt_start, blunt_start1, blunt_start2,
 696    lead_in, lead_in1, lead_in2,
 697    lead_in_ang, lead_in_ang1, lead_in_ang2,
 698    end_len, end_len1, end_len2,
 699    lead_in_shape="default",
 700    anchor, spin, orient
 701) {
 702    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
 703    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
 704    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
 705             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
 706             assert(thread_angle<=90 || all_positive([thread_depth]),
 707                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
 708    depth = first_defined([thread_depth,pitch/2]);
 709    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
 710    dummy2 = assert(pitch==0 || pa_delta<1/4, "Specified thread geometry is impossible");
 711    rr1 = -depth/pitch;
 712    z1 = 1/4-pa_delta;
 713    z2 = 1/4+pa_delta;
 714    profile = [
 715               [-z2, rr1],
 716               [-z1,  0],
 717               [ z1,  0],
 718               [ z2, rr1],
 719              ];
 720    generic_threaded_nut(nutwidth=nutwidth,id=id,h=h,pitch=pitch,profile=profile,id1=id1,id2=id2,
 721                         shape=shape,left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,
 722                         ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,bevang=bevang,height=height,thickness=thickness,
 723                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 724                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 725                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 726                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 727                         l=l,length=length,
 728                         anchor=anchor,spin=spin,orient=orient)
 729      children();
 730}
 731
 732
 733// Module: acme_threaded_rod()
 734// Synopsis: Creates an ACME threaded rod.
 735// SynTags: Geom
 736// Topics: Threading, Screws
 737// See Also: acme_threaded_nut()
 738// Usage:
 739//   acme_threaded_rod(d, l|length, tpi|pitch=, [internal=], ...) [ATTACHMENTS];
 740// Description:
 741//   Constructs an ACME trapezoidal threaded screw rod.  This form has a 29 degree thread angle with a
 742//   symmetric trapezoidal thread.  
 743// Arguments:
 744//   d = Outer diameter of threaded rod.
 745//   l / length / h / height = Length of threaded rod.
 746//   tpi = threads per inch.
 747//   ---
 748//   pitch = thread spacing (alternative to tpi)
 749//   starts = The number of lead starts.  Default = 1
 750//   left_handed = if true, create left-handed threads.  Default = false
 751//   bevel = if true, bevel the thread ends.  Default: false
 752//   bevel1 = if true bevel the bottom end.
 753//   bevel2 = if true bevel the top end. 
 754//   internal = If true, this is a mask for making internal threads.
 755//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 756//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 757//   blunt_start2 = If true apply truncated blunt start threads top end.
 758//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 759//   end_len1 = Specify unthreaded length at the bottom
 760//   end_len2 = Specify unthreaded length at the top
 761//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 762//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 763//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 764//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 765//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 766//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 767//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 768//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop. Default: false
 769//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 770//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 771//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 772//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 773// Example(2D):
 774//   projection(cut=true)
 775//       acme_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
 776// Examples(Med):
 777//   acme_threaded_rod(d=3/8*INCH, l=20, pitch=1/8*INCH, $fn=32);
 778//   acme_threaded_rod(d=10, l=30, pitch=2, starts=3, $fa=1, $fs=1);
 779// Example(Med;VPR=[100,0,5];VPD=220): Masking a Horizontal Threaded Hole
 780//   difference() {
 781//     cuboid(50);
 782//     acme_threaded_rod(
 783//         d=25, l=51, pitch=4, $fn=36,
 784//         internal=true, bevel=true,
 785//         blunt_start=false,
 786//         teardrop=true, orient=FWD
 787//     );
 788//   }
 789function acme_threaded_rod(
 790    d, l, tpi, pitch,
 791    starts=1,
 792    left_handed=false,
 793    bevel,bevel1,bevel2,
 794    internal=false, 
 795    d1, d2, length, h, height,
 796    blunt_start, blunt_start1, blunt_start2,
 797    lead_in, lead_in1, lead_in2,
 798    lead_in_ang, lead_in_ang1, lead_in_ang2,
 799    end_len, end_len1, end_len2,
 800    lead_in_shape="default",
 801    teardrop=false,
 802    anchor, spin, orient
 803) = no_function("acme_threaded_rod");
 804module acme_threaded_rod(
 805    d, l, tpi, pitch,
 806    starts=1,
 807    left_handed=false,
 808    bevel,bevel1,bevel2,
 809    internal=false, 
 810    d1, d2, length, h, height,
 811    blunt_start, blunt_start1, blunt_start2,
 812    lead_in, lead_in1, lead_in2,
 813    lead_in_ang, lead_in_ang1, lead_in_ang2,
 814    end_len, end_len1, end_len2,
 815    lead_in_shape="default",
 816    teardrop=false,
 817    anchor, spin, orient
 818) {
 819    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
 820    pitch = is_undef(pitch) ? INCH/tpi : pitch;
 821    trapezoidal_threaded_rod(
 822        d=d, l=l, pitch=pitch,
 823        thread_angle=29,
 824        thread_depth=pitch/2,
 825        starts=starts,
 826        left_handed=left_handed,
 827        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 828        internal=internal, length=length, height=height, h=h,
 829        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 830        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 831        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 832        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 833        teardrop=teardrop,
 834        anchor=anchor,
 835        spin=spin,
 836        orient=orient
 837    ) children();
 838}
 839
 840
 841
 842// Module: acme_threaded_nut()
 843// Synopsis: Creates an ACME threaded nut.
 844// SynTags: Geom
 845// Topics: Threading, Screws
 846// See Also: acme_threaded_rod()
 847// Usage:
 848//   acme_threaded_nut(nutwidth, id, h|height|thickness, tpi|pitch=, [shape=], ...) [ATTACHMENTS];
 849// Description:
 850//   Constructs a hexagonal or square nut for an ACME threaded screw rod. 
 851// Arguments:
 852//   nutwidth = flat to flat width of nut.
 853//   id = inner diameter of threaded hole, measured from bottom of threads
 854//   h / height / l / length / thickness = height/thickness of nut.
 855//   tpi = threads per inch
 856//   ---
 857//   pitch = Thread spacing (alternative to tpi)
 858//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 859//   left_handed = if true, create left-handed threads.  Default = false
 860//   starts = Number of lead starts.  Default: 1
 861//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 862//   bevel1 = if true, bevel the outside of the nut bottom.
 863//   bevel2 = if true, bevel the outside of the nut top. 
 864//   bevang = set the angle for the outside nut bevel.  Default: 30
 865//   ibevel = if true, bevel the inside (the hole).   Default: true
 866//   ibevel1 = if true bevel the inside, bottom end.
 867//   ibevel2 = if true bevel the inside, top end.
 868//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 869//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 870//   blunt_start2 = If true apply truncated blunt start threads top end.
 871//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 872//   end_len1 = Specify unthreaded length at the bottom
 873//   end_len2 = Specify unthreaded length at the top
 874//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 875//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 876//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 877//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 878//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 879//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 880//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 881//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 882//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 883//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 884//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 885// Examples(Med):
 886//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=8, tpi=8, $slop=0.05);
 887//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=10, tpi=12, starts=3, $slop=0.1, $fa=1, $fs=1, ibevel=false);
 888//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=10, tpi=12, starts=3, $slop=0.1, $fa=1, $fs=1, blunt_start=false);
 889function acme_threaded_nut(
 890    nutwidth, id, h, tpi, pitch,
 891    starts=1,
 892    left_handed=false,shape="hex",
 893    bevel,bevel1,bevel2,bevang=30,
 894    ibevel,ibevel1,ibevel2,
 895    height,thickness,
 896    length, l,
 897    blunt_start, blunt_start1, blunt_start2,
 898    lead_in, lead_in1, lead_in2,
 899    lead_in_ang, lead_in_ang1, lead_in_ang2,
 900    end_len, end_len1, end_len2,
 901    lead_in_shape="default",
 902    anchor, spin, orient
 903) = no_function("acme_threaded_nut");
 904module acme_threaded_nut(
 905    nutwidth, id, h, tpi, pitch,
 906    starts=1,
 907    left_handed=false,shape="hex",
 908    bevel,bevel1,bevel2,bevang=30,
 909    ibevel,ibevel1,ibevel2,
 910    height,thickness,
 911    length, l,
 912    blunt_start, blunt_start1, blunt_start2,
 913    lead_in, lead_in1, lead_in2,
 914    lead_in_ang, lead_in_ang1, lead_in_ang2,
 915    end_len, end_len1, end_len2,
 916    lead_in_shape="default",
 917    anchor, spin, orient
 918) {
 919    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
 920    pitch = is_undef(pitch) ? INCH/tpi : pitch;
 921    dummy2=assert(is_num(pitch) && pitch>=0);
 922    trapezoidal_threaded_nut(
 923        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
 924        thread_depth = pitch/2, 
 925        thread_angle=29,shape=shape, 
 926        left_handed=left_handed,
 927        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 928        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
 929        height=height,thickness=thickness,
 930        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 931        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 932        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 933        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 934        l=l,length=length,
 935        starts=starts,
 936        anchor=anchor,
 937        spin=spin,
 938        orient=orient
 939    ) children();
 940}
 941
 942
 943
 944
 945// Section: Pipe Threading
 946
 947// Module: npt_threaded_rod()
 948// Synopsis: Creates NPT pipe threading.
 949// SynTags: Geom
 950// Topics: Threading, Screws
 951// See Also: acme_threaded_rod()
 952// Usage:
 953//   npt_threaded_rod(size, [internal=], ...) [ATTACHMENTS];
 954// Description:
 955//   Constructs a standard NPT pipe end threading. If `internal=true`, creates a mask for making
 956//   internal pipe threads.  Tapers smaller upwards if `internal=false`.  Tapers smaller downwards
 957//   if `internal=true`.  If `hollow=true` and `internal=false`, then the pipe threads will be
 958//   hollowed out into a pipe with the apropriate internal diameter.
 959// Arguments:
 960//   size = NPT standard pipe size in inches.  1/16", 1/8", 1/4", 3/8", 1/2", 3/4", 1", 1+1/4", 1+1/2", or 2".  Default: 1/2"
 961//   ---
 962//   left_handed = If true, create left-handed threads.  Default = false
 963//   bevel = if true, bevel the thread ends.  Default: false
 964//   bevel1 = if true bevel the bottom end.
 965//   bevel2 = if true bevel the top end. 
 966//   hollow = If true, create a pipe with the correct internal diameter.
 967//   internal = If true, make this a mask for making internal threads.
 968//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 969//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 970//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 971//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 972// Example(2D): The straight gray rectangle reveals the tapered threads.  
 973//   projection(cut=true) npt_threaded_rod(size=1/4, orient=BACK);
 974//   right(.533*INCH/2) color("gray") rect([2,0.5946*INCH],anchor=LEFT);
 975// Examples(Med):
 976//   npt_threaded_rod(size=3/8, $fn=72);
 977//   npt_threaded_rod(size=1/2, $fn=72, bevel=true);
 978//   npt_threaded_rod(size=1/2, left_handed=true, $fn=72);
 979//   npt_threaded_rod(size=3/4, hollow=true, $fn=96);
 980// Example:
 981//   diff("remove"){
 982//      cuboid([40,40,40])
 983//      tag("remove"){
 984//        up(.01)position(TOP)
 985//            npt_threaded_rod(size=3/4, $fn=96, internal=true, $slop=0.1, anchor=TOP);
 986//        cyl(d=3/4*INCH, l=42, $fn=32);
 987//      }
 988//   }
 989function npt_threaded_rod(
 990    size=1/2,
 991    left_handed=false,
 992    bevel,bevel1,bevel2,
 993    hollow=false,
 994    internal=false,
 995    anchor, spin, orient
 996)=no_function("npt_threaded_rod");
 997module npt_threaded_rod(
 998    size=1/2,
 999    left_handed=false,
1000    bevel,bevel1,bevel2,
1001    hollow=false,
1002    internal=false,
1003    anchor, spin, orient
1004) {
1005    assert(is_finite(size));
1006    assert(is_bool(left_handed));
1007    assert(is_undef(bevel) || is_bool(bevel));
1008    assert(is_bool(hollow));
1009    assert(is_bool(internal));
1010    assert(!(internal&&hollow), "Cannot created a hollow internal threads mask.");
1011    info_table = [
1012        // Size    len      OD    TPI
1013        [ 1/16,  [ 0.3896, 0.308, 27  ]],
1014        [ 1/8,   [ 0.3924, 0.401, 27  ]],
1015        [ 1/4,   [ 0.5946, 0.533, 18  ]],
1016        [ 3/8,   [ 0.6006, 0.668, 18  ]],
1017        [ 1/2,   [ 0.7815, 0.832, 14  ]],
1018        [ 3/4,   [ 0.7935, 1.043, 14  ]],
1019        [ 1,     [ 0.9845, 1.305, 11.5]],
1020        [ 1+1/4, [ 1.0085, 1.649, 11.5]],
1021        [ 1+1/2, [ 1.0252, 1.888, 11.5]],
1022        [ 2,     [ 1.0582, 2.362, 11.5]],
1023    ];
1024    info = [for (data=info_table) if(approx(size,data[0])) data[1]][0];
1025    dummy1 = assert(is_def(info), "Unsupported NPT size.  Try one of 1/16, 1/8, 1/4, 3/8, 1/2, 3/4, 1, 1+1/4, 1+1/2, 2");
1026    l = INCH * info[0];
1027    d = INCH * info[1];
1028    pitch = INCH / info[2];
1029    rr = d/2;
1030    rr2 = rr - l/32;
1031    r1 = internal? rr2 : rr;
1032    r2 = internal? rr : rr2;
1033    depth = pitch * cos(30) * 5/8;
1034    profile = internal? [
1035        [-6/16, -depth/pitch],
1036        [-1/16,  0],
1037        [-1/32,  0.02],
1038        [ 1/32,  0.02],
1039        [ 1/16,  0],
1040        [ 6/16, -depth/pitch]
1041    ] : [
1042        [-7/16, -depth/pitch*1.07],
1043        [-6/16, -depth/pitch],
1044        [-1/16,  0],
1045        [ 1/16,  0],
1046        [ 6/16, -depth/pitch],
1047        [ 7/16, -depth/pitch*1.07]
1048    ];
1049    attachable(anchor,spin,orient, l=l, r1=r1, r2=r2) {
1050        difference() {
1051            generic_threaded_rod(
1052                d1=2*r1, d2=2*r2, l=l,
1053                pitch=pitch,
1054                profile=profile,
1055                left_handed=left_handed,
1056                bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1057                internal=internal,
1058                blunt_start=true
1059            );
1060            if (hollow) cylinder(h=l+1, d=size*INCH, center=true);
1061        }
1062        children();
1063    }
1064}
1065
1066
1067
1068// Section: Buttress Threading
1069
1070// Module: buttress_threaded_rod()
1071// Synopsis: Creates a buttress-threaded rod.
1072// SynTags: Geom
1073// Topics: Threading, Screws
1074// See Also: buttress_threaded_nut()
1075// Usage:
1076//   buttress_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
1077// Description:
1078//   Constructs a simple buttress threaded rod with a 45 degree angle.  The buttress thread or sawtooth thread has low friction and high loading
1079//   in one direction at the cost of higher friction and inferior loading in the other direction.  Buttress threads are sometimes used on
1080//   vises, which are loaded only in one direction.  
1081// Arguments:
1082//   d = Outer diameter of threaded rod.
1083//   l / length / h / height = Length of threaded rod.
1084//   pitch = Thread spacing.
1085//   ---
1086//   left_handed = if true, create left-handed threads.  Default = false
1087//   starts = Number of lead starts.  Default: 1
1088//   bevel = if true, bevel the thread ends.  Default: false
1089//   bevel1 = if true bevel the bottom end.
1090//   bevel2 = if true bevel the top end. 
1091//   internal = If true, this is a mask for making internal threads.
1092//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1093//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1094//   blunt_start2 = If true apply truncated blunt start threads top end.
1095//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1096//   end_len1 = Specify unthreaded length at the bottom
1097//   end_len2 = Specify unthreaded length at the top
1098//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1099//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1100//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1101//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1102//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1103//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1104//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1105//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop. Default: false
1106//   d1 = Bottom outside diameter of threads.
1107//   d2 = Top outside diameter of threads.
1108//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1109//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1110//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1111//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1112// Example(2D):
1113//   projection(cut=true)
1114//       buttress_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
1115// Examples(Med):
1116//   buttress_threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1,end_len=0);
1117//   buttress_threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
1118// Example(Med;VPR=[100,0,5];VPD=220): Masking a Horizontal Threaded Hole
1119//   difference() {
1120//     cuboid(50);
1121//     buttress_threaded_rod(
1122//         d=25, l=51, pitch=4, $fn=36,
1123//         internal=true, bevel=true,
1124//         blunt_start=false,
1125//         teardrop=true, orient=FWD
1126//     );
1127//   }
1128function buttress_threaded_rod(
1129    d, l, pitch,
1130    left_handed=false, starts=1,
1131    bevel,bevel1,bevel2,
1132    internal=false,
1133    d1, d2, length, h, height,
1134    blunt_start, blunt_start1, blunt_start2,
1135    lead_in, lead_in1, lead_in2,
1136    lead_in_ang, lead_in_ang1, lead_in_ang2,
1137    end_len, end_len1, end_len2,
1138    lead_in_shape="default",
1139    teardrop=false,
1140    anchor, spin, orient
1141) = no_function("buttress_threaded_rod");
1142module buttress_threaded_rod(
1143    d, l, pitch,
1144    left_handed=false, starts=1,
1145    bevel,bevel1,bevel2,
1146    internal=false,
1147    d1, d2, length, h, height,
1148    blunt_start, blunt_start1, blunt_start2,
1149    lead_in, lead_in1, lead_in2,
1150    lead_in_ang, lead_in_ang1, lead_in_ang2,
1151    end_len, end_len1, end_len2,
1152    lead_in_shape="default",
1153    teardrop=false,
1154    anchor, spin, orient
1155) {
1156    depth = pitch * 3/4;
1157    profile = [
1158        [  -1/2, -0.77],
1159        [ -7/16, -0.75],
1160        [  5/16,  0],
1161        [  7/16,  0],
1162        [  7/16, -0.75],
1163        [   1/2, -0.77],
1164    ];
1165    generic_threaded_rod(
1166        d=d, l=l, pitch=pitch,
1167        profile=profile, 
1168        left_handed=left_handed,
1169        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1170        internal=internal, length=length, height=height, h=h,
1171        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1172        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1173        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1174        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1175        d1=d1,d2=d2,
1176        teardrop=teardrop,
1177        anchor=anchor,
1178        spin=spin,starts=starts,
1179        orient=orient
1180    ) children();
1181}
1182
1183
1184
1185// Module: buttress_threaded_nut()
1186// Synopsis: Creates a buttress-threaded nut.
1187// SynTags: Geom
1188// Topics: Threading, Screws
1189// See Also: buttress_threaded_rod()
1190// Usage:
1191//   buttress_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
1192// Description:
1193//   Constructs a hexagonal or square nut for a simple buttress threaded screw rod.  
1194// Arguments:
1195//   nutwidth = diameter of the nut.
1196//   id = inner diameter of threaded hole, measured from bottom of threads
1197//   h / height / l / length / thickness = height/thickness of nut.
1198//   pitch = Thread spacing. 
1199//   ---
1200//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1201//   left_handed = if true, create left-handed threads.  Default = false
1202//   starts = The number of lead starts.  Default: 1
1203//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1204//   bevel1 = if true, bevel the outside of the nut bottom.
1205//   bevel2 = if true, bevel the outside of the nut top. 
1206//   bevang = set the angle for the outside nut bevel.  Default: 30
1207//   ibevel = if true, bevel the inside (the hole).   Default: true
1208//   ibevel1 = if true bevel the inside, bottom end.
1209//   ibevel2 = if true bevel the inside, top end.
1210//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1211//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1212//   blunt_start2 = If true apply truncated blunt start threads top end.
1213//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1214//   end_len1 = Specify unthreaded length at the bottom
1215//   end_len2 = Specify unthreaded length at the top
1216//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1217//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1218//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1219//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1220//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1221//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1222//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1223//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1224//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1225//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1226//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1227// Examples(Med):
1228//   buttress_threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, $slop=0.05, $fa=1, $fs=1);
1229function buttress_threaded_nut(
1230    nutwidth, id, h,
1231    pitch, shape="hex", left_handed=false,
1232    bevel,bevel1,bevel2,bevang=30,starts=1,
1233    ibevel,ibevel1,ibevel2,height,thickness,
1234    length, l,
1235    blunt_start, blunt_start1, blunt_start2,
1236    lead_in, lead_in1, lead_in2,
1237    lead_in_ang, lead_in_ang1, lead_in_ang2,
1238    end_len, end_len1, end_len2,
1239    lead_in_shape="default",
1240    anchor, spin, orient
1241) = no_function("buttress_threaded_nut");
1242module buttress_threaded_nut(
1243    nutwidth, id, h,
1244    pitch, shape="hex", left_handed=false,
1245    bevel,bevel1,bevel2,bevang=30,starts=1,
1246    ibevel,ibevel1,ibevel2,height,thickness,
1247    length, l,
1248    blunt_start, blunt_start1, blunt_start2,
1249    lead_in, lead_in1, lead_in2,
1250    lead_in_ang, lead_in_ang1, lead_in_ang2,
1251    end_len, end_len1, end_len2,
1252    lead_in_shape="default",
1253    anchor, spin, orient
1254) {
1255    depth = pitch * 3/4;
1256    profile = [
1257        [  -1/2, -0.77],
1258        [ -7/16, -0.75],
1259        [  5/16,  0],
1260        [  7/16,  0],
1261        [  7/16, -0.75],
1262        [  1/ 2, -0.77],
1263    ];
1264    generic_threaded_nut(
1265        nutwidth=nutwidth, id=id, h=h,
1266        pitch=pitch,
1267        profile=profile,
1268        shape=shape,
1269        left_handed=left_handed,starts=starts,
1270        bevel=bevel,bevel1=bevel1,bevel2=bevel2,bevang=bevang,
1271        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
1272        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1273        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1274        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1275        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1276        l=l,length=length,
1277        anchor=anchor, spin=spin, height=height, thickness=thickness, 
1278        orient=orient
1279    ) children();
1280}
1281
1282
1283
1284// Section: Square Threading
1285
1286// Module: square_threaded_rod()
1287// Synopsis: Creates a square-threaded rod.
1288// SynTags: Geom
1289// Topics: Threading, Screws
1290// See Also: square_threaded_nut()
1291// Usage:
1292//   square_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
1293// Description:
1294//   Constructs a square profile threaded screw rod.  The greatest advantage of square threads is
1295//   that they have the least friction and a much higher intrinsic efficiency than trapezoidal threads.
1296//   They produce no radial load on the nut.  However, square threads cannot carry as much load as trapezoidal threads. 
1297// Arguments:
1298//   d = Outer diameter of threaded rod.
1299//   l / length / h / height = Length of threaded rod.
1300//   pitch = Thread spacing.
1301//   ---
1302//   left_handed = if true, create left-handed threads.  Default = false
1303//   starts = The number of lead starts.  Default = 1
1304//   bevel = if true, bevel the thread ends.  Default: false
1305//   bevel1 = if true bevel the bottom end.
1306//   bevel2 = if true bevel the top end. 
1307//   internal = If true, this is a mask for making internal threads.
1308//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1309//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1310//   blunt_start2 = If true apply truncated blunt start threads top end.
1311//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1312//   end_len1 = Specify unthreaded length at the bottom
1313//   end_len2 = Specify unthreaded length at the top
1314//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1315//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1316//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1317//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1318//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1319//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1320//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1321//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop. Default: false
1322//   d1 = Bottom outside diameter of threads.
1323//   d2 = Top outside diameter of threads.
1324//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1325//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1326//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1327//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1328// Example(2D):
1329//   projection(cut=true)
1330//       square_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
1331// Examples(Med):
1332//   square_threaded_rod(d=10, l=20, pitch=2, starts=2, $fn=32);
1333// Example(Med;VPR=[100,0,5];VPD=220): Masking a Horizontal Threaded Hole
1334//   difference() {
1335//     cuboid(50);
1336//     square_threaded_rod(
1337//         d=25, l=51, pitch=4, $fn=36,
1338//         internal=true, bevel=true,
1339//         blunt_start=false,
1340//         teardrop=true, orient=FWD
1341//     );
1342//   }
1343function square_threaded_rod(
1344    d, l, pitch,
1345    left_handed=false,
1346    bevel,bevel1,bevel2,
1347    starts=1,
1348    internal=false,
1349    d1, d2, length, h, height,
1350    blunt_start, blunt_start1, blunt_start2,
1351    lead_in, lead_in1, lead_in2,
1352    lead_in_ang, lead_in_ang1, lead_in_ang2,
1353    end_len, end_len1, end_len2,
1354    lead_in_shape="default",
1355    teardrop=false,
1356    anchor, spin, orient
1357) = no_function("square_threaded_rod");
1358module square_threaded_rod(
1359    d, l, pitch,
1360    left_handed=false,
1361    bevel,bevel1,bevel2,
1362    starts=1,
1363    internal=false,
1364    d1, d2, length, h, height,
1365    blunt_start, blunt_start1, blunt_start2,
1366    lead_in, lead_in1, lead_in2,
1367    lead_in_ang, lead_in_ang1, lead_in_ang2,
1368    end_len, end_len1, end_len2,
1369    lead_in_shape="default",
1370    teardrop=false,
1371    anchor, spin, orient
1372) {
1373    trapezoidal_threaded_rod(
1374        d=d, l=l, pitch=pitch,
1375        thread_angle=0.1,
1376        left_handed=left_handed,
1377        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1378        starts=starts,
1379        internal=internal, length=length, height=height, h=h,
1380        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1381        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1382        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1383        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1384        teardrop=teardrop,
1385        d1=d1, d2=d2,
1386        anchor=anchor,
1387        spin=spin,
1388        orient=orient
1389    ) children();
1390}
1391
1392
1393
1394// Module: square_threaded_nut()
1395// Synopsis: Creates a square-threaded nut.
1396// SynTags: Geom
1397// Topics: Threading, Screws
1398// See Also: square_threaded_rod()
1399// Usage:
1400//   square_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
1401// Description:
1402//   Constructs a hexagonal or square nut for a square profile threaded screw rod.  
1403// Arguments:
1404//   nutwidth = diameter of the nut.
1405//   id = inner diameter of threaded hole, measured from bottom of threads
1406//   h / height / l / length / thickness = height/thickness of nut.
1407//   pitch = Length between threads.
1408//   ---
1409//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1410//   left_handed = if true, create left-handed threads.  Default = false
1411//   starts = The number of lead starts.  Default = 1
1412//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1413//   bevel1 = if true, bevel the outside of the nut bottom.
1414//   bevel2 = if true, bevel the outside of the nut top. 
1415//   bevang = set the angle for the outside nut bevel.  Default: 30
1416//   ibevel = if true, bevel the inside (the hole).   Default: true
1417//   ibevel1 = if true bevel the inside, bottom end.
1418//   ibevel2 = if true bevel the inside, top end.
1419//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1420//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1421//   blunt_start2 = If true apply truncated blunt start threads top end.
1422//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1423//   end_len1 = Specify unthreaded length at the bottom
1424//   end_len2 = Specify unthreaded length at the top
1425//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1426//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1427//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1428//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1429//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1430//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1431//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1432//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1433//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1434//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1435//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1436// Examples(Med):
1437//   square_threaded_nut(nutwidth=16, id=10, h=10, pitch=2, starts=2, $slop=0.1, $fn=32);
1438function square_threaded_nut(
1439    nutwidth, id, h,
1440    pitch,
1441    left_handed=false,
1442    bevel,bevel1,bevel2,bevang=30,
1443    ibevel,ibevel1,ibevel2,
1444    height,thickness,    
1445    length, l,
1446    blunt_start, blunt_start1, blunt_start2,
1447    lead_in, lead_in1, lead_in2,
1448    lead_in_ang, lead_in_ang1, lead_in_ang2,
1449    end_len, end_len1, end_len2,
1450    lead_in_shape="default",
1451    starts=1,
1452    anchor, spin, orient
1453) = no_function("square_threaded_nut");
1454module square_threaded_nut(
1455    nutwidth, id, h,
1456    pitch,
1457    left_handed=false,
1458    bevel,bevel1,bevel2,bevang=30,
1459    ibevel,ibevel1,ibevel2,
1460    height,thickness,    
1461    length, l,
1462    blunt_start, blunt_start1, blunt_start2,
1463    lead_in, lead_in1, lead_in2,
1464    lead_in_ang, lead_in_ang1, lead_in_ang2,
1465    end_len, end_len1, end_len2,
1466    lead_in_shape="default",
1467    starts=1,
1468    anchor, spin, orient
1469) {
1470    assert(is_num(pitch) && pitch>=0)
1471    trapezoidal_threaded_nut(
1472        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
1473        thread_angle=0,
1474        left_handed=left_handed,
1475        bevel=bevel,bevel1=bevel1,bevel2=bevel2, bevang=bevang,
1476        ibevel=ibevel, ibevel1=ibevel1, ibevel2=ibevel2,
1477        height=height,thickness=thickness,
1478        starts=starts,
1479        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1480        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1481        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1482        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1483        l=l,length=length,
1484        anchor=anchor,
1485        spin=spin,
1486        orient=orient
1487    ) children();
1488}
1489
1490
1491// Section: Ball Screws
1492
1493// Module: ball_screw_rod()
1494// Synopsis: Creates a ball screw rod.
1495// SynTags: Geom
1496// Topics: Threading, Screws
1497// Usage:
1498//   ball_screw_rod(d, l|length, pitch, [ball_diam], [ball_arc], [internal=], ...) [ATTACHMENTS];
1499// Description:
1500//   Constructs a ball screw rod.  This type of rod is used with ball bearings.  
1501// Arguments:
1502//   d = Outer diameter of threaded rod.
1503//   l / length / h / height = Length of threaded rod.
1504//   pitch = Thread spacing. Also, the diameter of the ball bearings used.
1505//   ball_diam = The diameter of the ball bearings to use with this ball screw.
1506//   ball_arc = The arc portion that should touch the ball bearings. Default: 120 degrees.
1507//   ---
1508//   left_handed = if true, create left-handed threads.  Default = false
1509//   starts = The number of lead starts.  Default = 1
1510//   bevel = if true, bevel the thread ends.  Default: false
1511//   bevel1 = if true bevel the bottom end.
1512//   bevel2 = if true bevel the top end. 
1513//   internal = If true, make this a mask for making internal threads.
1514//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1515//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1516//   blunt_start2 = If true apply truncated blunt start threads top end.
1517//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1518//   end_len1 = Specify unthreaded length at the bottom
1519//   end_len2 = Specify unthreaded length at the top
1520//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1521//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1522//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1523//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1524//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1525//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1526//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1527//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1528//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1529//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1530//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1531// Example(2D): Thread Profile, ball_diam=4, ball_arc=100
1532//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=4, ball_arc=100, orient=BACK, $fn=24, blunt_start=false);
1533// Example(2D): Thread Profile, ball_diam=4, ball_arc=120
1534//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=4, ball_arc=120, orient=BACK, $fn=24, blunt_start=false);
1535// Example(2D): Thread Profile, ball_diam=3, ball_arc=120
1536//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=3, ball_arc=120, orient=BACK, $fn=24, blunt_start=false);
1537// Examples(Med):
1538//   ball_screw_rod(d=15, l=20, pitch=8, ball_diam=5, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
1539//   ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
1540//   ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, left_handed=true, $fa=1, $fs=0.5, blunt_start=false);
1541function ball_screw_rod(
1542    d, l, pitch, 
1543    ball_diam=5, ball_arc=100,
1544    starts=1,
1545    left_handed=false,
1546    internal=false,
1547    length, h, height,
1548    bevel, bevel1, bevel2,
1549    blunt_start, blunt_start1, blunt_start2,
1550    lead_in, lead_in1, lead_in2,
1551    lead_in_ang, lead_in_ang1, lead_in_ang2,
1552    end_len, end_len1, end_len2,
1553    lead_in_shape="default",
1554    anchor, spin, orient
1555) = no_function("ball_screw_rod");
1556module ball_screw_rod(
1557    d, l, pitch, 
1558    ball_diam=5, ball_arc=100,
1559    starts=1,
1560    left_handed=false,
1561    internal=false,
1562    length, h, height,
1563    bevel, bevel1, bevel2,
1564    blunt_start, blunt_start1, blunt_start2,
1565    lead_in, lead_in1, lead_in2,
1566    lead_in_ang, lead_in_ang1, lead_in_ang2,
1567    end_len, end_len1, end_len2,
1568    lead_in_shape="default",
1569    anchor, spin, orient
1570) {
1571    n = max(3,ceil(segs(ball_diam/2)*ball_arc/2/360));
1572    depth = ball_diam * (1-cos(ball_arc/2))/2;
1573    cpy = ball_diam/2/pitch*cos(ball_arc/2);
1574    profile = [
1575        each arc(n=n, d=ball_diam/pitch, cp=[-0.5,cpy], start=270, angle=ball_arc/2),
1576        each arc(n=n, d=ball_diam/pitch, cp=[+0.5,cpy], start=270-ball_arc/2, angle=ball_arc/2)
1577    ];
1578    generic_threaded_rod(
1579        d=d, l=l, pitch=pitch,
1580        profile=profile,
1581        left_handed=left_handed,
1582        starts=starts,
1583        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1584        internal=internal, length=length, height=height, h=h,
1585        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1586        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1587        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1588        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1589        anchor=anchor,
1590        spin=spin,
1591        orient=orient
1592    ) children();
1593}
1594
1595
1596// Section: Generic Threading
1597
1598// Module: generic_threaded_rod()
1599// Synopsis: Creates a generic threaded rod.
1600// SynTags: Geom
1601// Topics: Threading, Screws
1602// See Also: generic_threaded_nut()
1603// Usage:
1604//   generic_threaded_rod(d, l|length, pitch, profile, [internal=], ...) [ATTACHMENTS];
1605// Description:
1606//   Constructs a generic threaded rod using an arbitrary thread profile that you supply.  The rod can be tapered
1607//   (e.g. for pipe threads).  For specific thread types use other modules that supply the appropriate profile.
1608//   .
1609//   You give the profile as a 2D path that will be scaled by the pitch to produce the final thread shape.  The profile
1610//   X values must be between -1/2 and 1/2.  The Y=0 point will align with the specified rod diameter, so generally you
1611//   want a Y value of zero at the peak (which makes your specified diameter the outer diameter of the threads).  The
1612//   value in the valleys of the thread should then be `-depth/pitch` due to the scaling by the thread pitch.  The first
1613//   and last points should generally have the same Y value, but it is not necessary to give values at X=1/2 or X=-1/2
1614//   if unless the Y values differ from the interior points in the profile.  Generally you should center the profile
1615//   horizontally in the interval [-1/2, 1/2].
1616//   .
1617//   If internal is true then produce a thread mask to difference from an object.  When internal is true the rod
1618//   diameter is enlarged to correct for the polygonal nature of circles to ensure that the internal diameter is the
1619//   specified size.  The diameter is also increased by `4 * $slop` to create clearance for threading by allowing a `2 *
1620//   $slop` gap on each side.  If bevel is set to true and internal is false then the ends of the rod will be beveled.
1621//   When bevel is true and internal is true the ends of the rod will be filled in so that the rod mask will create a
1622//   bevel when subtracted from an object.  The bevel is at 45 deg and is the depth of the threads.
1623//   .
1624//   Blunt start threading, which is the default, specifies that the thread ends abruptly at its full width instead of
1625//   running off the end of the shaft and leaving a sharp edged partial thread at the end of the screw.  This makes
1626//   screws easier to start and prevents cross threading.  Blunt start threads should always be superior, and they are
1627//   faster to model, but if you really need standard threads that run off the end you can set `blunt_start=false`.
1628//   .
1629//   The teardrop option cuts off the threads with a teardrop for 3d printability of horizontal holes.  By default,
1630//   if the screw outer radius is r then the flat top will be at distance 1.05r from the center, adding a 5% space.  
1631//   You can set teardrop to a numerical value to adjust that percentage, e.g. a value of 0.1 would give a 10% space.
1632//   You can set teardrop to "max" to create a pointy-top teardrop with no flat section.  
1633// Arguments:
1634//   d = Outer diameter of threaded rod.
1635//   l / length / h / height = Length of threaded rod.
1636//   pitch = Thread spacing.
1637//   profile = A 2D path giving the shape of a thread
1638//   ---
1639//   left_handed = If true, create left-handed threads.  Default: false
1640//   starts = The number of lead starts.  Default: 1
1641//   internal = If true, make this a mask for making internal threads.  Default: false
1642//   d1 = Bottom outside diameter of threads.
1643//   d2 = Top outside diameter of threads.
1644//   bevel = set to true to bevel both ends, a number to specify a bevel size, false for no bevel, and "reverse" for an inverted bevel
1645//   bevel1 = set bevel for bottom end. 
1646//   bevel2 = set bevel for top end.
1647//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1648//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1649//   blunt_start2 = If true apply truncated blunt start threads top end.
1650//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1651//   end_len1 = Specify unthreaded length at the bottom
1652//   end_len2 = Specify unthreaded length at the top
1653//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1654//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1655//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1656//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1657//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1658//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1659//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1660//   teardrop = If true, adds a teardrop profile to the back (Y+) side of the threaded rod, for 3d printability of horizontal holes. If numeric, specifies the proportional extra distance of the teardrop flat top from the screw center, or set to "max" for a pointed teardrop (see above). Default: false
1661//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1662//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1663//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1664//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1665// Example(2DMed): Example Tooth Profile
1666//   pitch = 2;
1667//   depth = pitch * cos(30) * 5/8;
1668//   profile = [
1669//       [-7/16, -depth/pitch*1.07],
1670//       [-6/16, -depth/pitch],
1671//       [-1/16,  0],
1672//       [ 1/16,  0],
1673//       [ 6/16, -depth/pitch],
1674//       [ 7/16, -depth/pitch*1.07]
1675//   ];
1676//   stroke(profile, width=0.02);
1677// Example:
1678//   pitch = 2;
1679//   depth = pitch * cos(30) * 5/8;
1680//   profile = [
1681//       [-7/16, -depth/pitch*1.07],
1682//       [-6/16, -depth/pitch],
1683//       [-1/16,  0],
1684//       [ 1/16,  0],
1685//       [ 6/16, -depth/pitch],
1686//       [ 7/16, -depth/pitch*1.07]
1687//   ];
1688//   generic_threaded_rod(d=10, l=40, pitch=2, profile=profile);
1689
1690function generic_threaded_rod(
1691    d, l, pitch, profile,
1692    left_handed=false, internal=false,
1693    bevel, bevel1, bevel2, 
1694    starts=1,
1695    d1, d2, length, h, height,
1696    blunt_start, blunt_start1, blunt_start2,
1697    lead_in, lead_in1, lead_in2,
1698    lead_in_ang, lead_in_ang1, lead_in_ang2,
1699    end_len, end_len1, end_len2,
1700    lead_in_shape="default",
1701    teardrop=false,
1702    anchor, spin, orient
1703) = no_function("generic_threaded_rod");
1704module generic_threaded_rod(
1705    d, l, pitch, profile,
1706    left_handed=false, internal=false,
1707    bevel, bevel1, bevel2, 
1708    starts=1,
1709    d1, d2, length, h, height,
1710    blunt_start, blunt_start1, blunt_start2,
1711    lead_in, lead_in1, lead_in2,
1712    lead_in_ang, lead_in_ang1, lead_in_ang2,
1713    end_len, end_len1, end_len2,
1714    lead_in_shape="default",
1715    teardrop=false,
1716    anchor, spin, orient
1717) {
1718    len = one_defined([l,length,h,height],"l,length,h,height");
1719    bevel1 = first_defined([bevel1,bevel]);
1720    bevel2 = first_defined([bevel2,bevel]);
1721    blunt_start1 = first_defined([blunt_start1, blunt_start, true]);
1722    blunt_start2 = first_defined([blunt_start2, blunt_start, true]);                           
1723    r1 = get_radius(d1=d1, d=d);
1724    r2 = get_radius(d1=d2, d=d);
1725    lead_in1 = first_defined([lead_in1, lead_in]);
1726    lead_in2 = first_defined([lead_in2, lead_in]);
1727    lead_in_func = is_func(lead_in_shape) ? lead_in_shape
1728                 : assert(is_string(lead_in_shape),"lead_in_shape must be a function or string")
1729                   let(ind = search([lead_in_shape], _lead_in_table,0)[0])
1730                   assert(ind!=[],str("Unknown lead_in_shape, \"",lead_in_shape,"\""))
1731                   _lead_in_table[ind[0]][1];
1732    dummy0 = 
1733      assert(all_positive([pitch]),"Thread pitch must be a positive value")
1734      assert(all_positive([len]),"Length must be a postive value")
1735      assert(is_path(profile),"Profile must be a path")
1736      assert(is_bool(blunt_start1), "blunt_start1/blunt_start must be boolean")
1737      assert(is_bool(blunt_start2), "blunt_start2/blunt_start must be boolean")
1738      assert(is_bool(left_handed))
1739      assert(all_positive([r1,r2]), "Must give d or both d1 and d2 as positive values")
1740      assert(is_undef(bevel1) || is_num(bevel1) || is_bool(bevel1) || bevel1=="reverse", "bevel1/bevel must be a number, boolean or \"reverse\"")
1741      assert(is_undef(bevel2) || is_num(bevel2) || is_bool(bevel2) || bevel2=="reverse", "bevel2/bevel must be a number, boolean or \"reverse\"");
1742    sides = quantup(segs(max(r1,r2)), starts);
1743    rsc = internal? (1/cos(180/sides)) : 1;    // Internal radius adjusted for faceting
1744    islop = internal? 2*get_slop() : 0;
1745    r1adj = r1 * rsc + islop;
1746    r2adj = r2 * rsc + islop;
1747
1748    extreme = internal? max(column(profile,1)) : min(column(profile,1));
1749    profile = !internal ? profile
1750            : let(
1751                 maxidx = [for(i=idx(profile)) if (profile[i].y==extreme) i],
1752                 cutpt = len(maxidx)==1 ? profile(maxidx[0]).x
1753                       : mean([profile[maxidx[0]].x, profile[maxidx[1]].x])
1754              )
1755              [
1756                 for(entry=profile) if (entry.x>=cutpt) [entry.x-cutpt-1/2,entry.y], 
1757                 for(entry=profile) if (entry.x<cutpt) [entry.x-cutpt+1/2,entry.y]
1758              ];
1759    profmin = pitch * min(column(profile,1));
1760    pmax = pitch * max(column(profile,1));
1761    rmax = max(r1adj,r2adj)+pmax;
1762
1763    // These parameters give the size of the bevel, negative for an outward bevel (e.g. on internal thread mask)  
1764    bev1 = (bevel1=="reverse"?-1:1)*(internal?-1:1) *
1765               ( is_num(bevel1)? bevel1
1766               : bevel1==false? 0
1767               : blunt_start1? (bevel1==undef?0
1768                               :internal ? r1/6
1769                               :(r1+profmin)/6)
1770               : pmax-profmin);
1771    bev2 = (bevel2=="reverse"?-1:1)*(internal?-1:1) *
1772               ( is_num(bevel2)? bevel2
1773               : bevel2==false? 0
1774               : blunt_start2? (bevel2==undef?0
1775                               :internal ? r2/6
1776                               :(r2+profmin)/6)
1777               : pmax-profmin);
1778    // This is the bevel size used for constructing the polyhedron.  The bevel is integrated when blunt start is on, but
1779    // applied later via difference/union if blunt start is off, so set bevel to zero in the latter case.  
1780    bevel_size1 = blunt_start1?bev1:0;
1781    bevel_size2 = blunt_start2?bev2:0;
1782    // This is the bevel size for clipping, which is only done when blunt start is off
1783    clip_bev1 = blunt_start1?0:bev1;
1784    clip_bev2 = blunt_start2?0:bev2;
1785    end_len1_base = !blunt_start1? 0 : first_defined([end_len1,end_len, 0]);
1786    end_len2_base = !blunt_start2? 0 : first_defined([end_len2,end_len, 0]);    
1787    // Enlarge end lengths to give sufficient room for requested bevel
1788    end_len1 = abs(bevel_size1)>0 ? max(end_len1_base, abs(bevel_size1)) : end_len1_base;
1789    end_len2 = abs(bevel_size2)>0 ? max(end_len2_base, abs(bevel_size2)) : end_len2_base;
1790    // length to create below/above z=0, with an extra revolution in non-blunt-start case so
1791    // the threads can continue to the specified length and we can clip off the blunt start                       
1792    len1 = -len/2 - (blunt_start1?0:pitch);   
1793    len2 =  len/2 + (blunt_start2?0:pitch);
1794
1795    // Thread turns below and above z=0, with extra to ensure we go beyond the length needed
1796    turns1 = len1/pitch-1;
1797    turns2 = len2/pitch+1;
1798    dir = left_handed? -1 : 1;
1799    dummy2=
1800        assert(abs(bevel_size1)+abs(bevel_size2)<len, "Combined bevel size exceeds length of screw")
1801        assert(r1adj+extreme*pitch-bevel_size1>0, "bevel1 is too large to fit screw diameter")
1802        assert(r2adj+extreme*pitch-bevel_size2>0, "bevel2 is too large to fit screw diameter");
1803         
1804    margin1 = profile[0].y==extreme ? profile[0].x : -1/2;
1805    margin2 = last(profile).y==extreme? last(profile).x : 1/2;
1806    lead_in_default = pmax-profmin;//2*pitch;
1807        // 0*360/10;// /4/32*360; higlen_default;//0*4/32*360; //2/32*360;//360*max(pitch/2, pmax-depth)/(2*PI*r2adj);
1808    // lead_in length needs to be quantized to match the samples
1809    lead_in_ang1 = !blunt_start1? 0 :
1810         let(
1811             user_ang = first_defined([lead_in_ang1,lead_in_ang])
1812         )
1813         assert(is_undef(user_ang) || is_undef(lead_in1), "Cannot define lead_in/lead_in1 by both length and angle")
1814         quantup(
1815                 is_def(user_ang) ? user_ang : default(lead_in1, lead_in_default)*360/(2*PI*r1adj)
1816                 , 360/sides);
1817    lead_in_ang2 = !blunt_start2? 0 :
1818         let(
1819             user_ang = first_defined([lead_in_ang2,lead_in_ang])
1820         )
1821         assert(is_undef(user_ang) || is_undef(lead_in2), "Cannot define lead_in/lead_in2 by both length and angle")
1822         quantup(
1823                 is_def(user_ang) ? user_ang : default(lead_in2, lead_in_default)*360/(2*PI*r2adj)
1824                 , 360/sides);
1825    // cut_ang also need to be quantized, but the comparison is offset by 36*turns1/starts, so we need to pull that factor out
1826    // of the quantization.  (The loop over angle starts at 360*turns1/starts, not at a multiple of 360/sides.)  
1827//    cut_ang1 = 360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1;
1828//    cut_ang2 = 360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2;
1829    cut_ang1 = quantup(360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1-360*turns1/starts,360/sides)+360*turns1/starts;
1830    cut_ang2 = quantdn(360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2-360*turns1/starts,360/sides)+360*turns1/starts;
1831    dummy1 =
1832      assert(cut_ang1<cut_ang2, "lead in length are too long for the amount of thread: they overlap")
1833      assert(is_num(lead_in_ang1), "lead_in1/lead_in must be a number")
1834      assert(r1adj+profmin>0 && r2adj+profmin>0, "Screw profile deeper than rod radius");
1835    map_threads = right((r1adj + r2adj) / 2)                   // Shift profile out to thread radius
1836                * affine3d_skew(sxz=(r2adj-r1adj)/len)         // Skew correction for tapered threads
1837                * frame_map(x=[0,0,1], y=[1,0,0])          // Map profile to 3d, parallel to z axis
1838                * scale(pitch);                            // scale profile by pitch
1839    start_steps = sides / starts;
1840
1841    // This is the location for clipping the polyhedron, below the bevel, if one is present, or at length otherwise
1842    // Clipping is done before scaling to pitch, so we need to divide by the pitch
1843    rod_clip1 = (len1+abs(bevel_size1))/pitch;
1844    rod_clip2 = (len2-abs(bevel_size2))/pitch;
1845    prof3d=path3d(profile,1);
1846    thread_verts = [
1847        // Outer loop constructs a vertical column of the screw at each angle
1848        // covering 360/starts degrees of the cylinder.  
1849        for (step = [0:1:start_steps])
1850            let(
1851                ang = 360 * step/sides,
1852                dz = step / start_steps,    // z offset for threads at this angle
1853                rot_prof = zrot(ang*dir)*map_threads,   // Rotate profile to correct angular location
1854                full_profile =  [   // profile for the entire rod
1855                    for (turns = [turns1:1:turns2]) 
1856                        let(
1857                            tang = turns/starts * 360 + ang,
1858                            // EPSILON offset prevents funny looking extensions of the thread from its very tip
1859                            // by forcing values near the tip to evaluate as less than zero = beyond the tip end
1860                            hsc = tang < cut_ang1 ? lead_in_func(-EPSILON+1-(cut_ang1-tang)/lead_in_ang1,PI*2*r1adj*lead_in_ang1/360 )
1861                                : tang > cut_ang2 ? lead_in_func(-EPSILON+1-(tang-cut_ang2)/lead_in_ang2,PI*2*r2adj*lead_in_ang2/360 )
1862                                : [1,1],
1863                            shift_and_scale = [[hsc.x, 0], [0,hsc.y], [dz+turns,(1-hsc.y)*extreme]]
1864                        )
1865                        // This is equivalent to apply(right(dz+turns)*higscale, profile)
1866                        //
1867                        // The right movement finds the position of the thread along
1868                        // what will be the z axis after the profile is mapped to 3d,
1869                        // and higscale creates a taper and the end of the threads.  
1870                        each prof3d*shift_and_scale
1871                ],
1872                // Clip profile at the ends of the rod and add a z coordinate
1873                full_profile_clipped = [
1874                    for(pts=full_profile) [max(rod_clip1,min(rod_clip2,pts.x)), pts.y, 0]
1875                ]
1876            )
1877            [
1878              [0,0,len1],
1879              //if (true) apply(rot_prof, [len1/pitch,extreme+2/pitch ,0]), 
1880              if (bevel_size1) apply(rot_prof, [len1/pitch,extreme-bevel_size1/pitch ,0]), 
1881              each apply(rot_prof, full_profile_clipped),
1882              if (bevel_size2) apply(rot_prof, [len2/pitch,extreme-bevel_size2/pitch ,0]), 
1883              //if (true) apply(rot_prof, [len2/pitch,extreme+2/pitch ,0]), 
1884              [0, 0, len2]
1885            ]
1886    ];
1887    style=internal?"concave":"convex";
1888    thread_vnf = vnf_join([
1889                           for (i=[0:1:starts-1])
1890                             zrot(i*360/starts, p=vnf_vertex_array(thread_verts, reverse=left_handed, style=style,col_wrap=false)),
1891                          ]);
1892    slope = (r1adj-r2adj)/len;
1893    dummy3 = 
1894      assert(r1adj+pmax-clip_bev1>0, "bevel1 is too large to fit screw diameter")
1895      assert(r2adj+pmax-clip_bev2>0, "bevel2 is too large to fit screw diameter")
1896      assert(abs(clip_bev1)+abs(clip_bev2)<len, "Combined bevel size exceeds length of screw");
1897    attachable(anchor,spin,orient, r1=r1adj, r2=r2adj, l=len) {
1898        union(){
1899          difference() {
1900              vnf_polyhedron(thread_vnf,convexity=10);              
1901              if (clip_bev1>0)
1902                  rotate_extrude()
1903                      polygon([[                         0,-len/2],
1904                               [r1adj+pmax-clip_bev1      ,-len/2],
1905                               [r1adj+pmax-slope*clip_bev1,-len/2+clip_bev1],
1906                               [                    rmax+1,-len/2+clip_bev1],
1907                               [                    rmax+1, len1-1],
1908                               [                         0, len1-1]]);
1909              if (clip_bev2>0)
1910                  rotate_extrude()
1911                      polygon([[                         0, len/2],
1912                               [r2adj+pmax-clip_bev2      , len/2],
1913                               [r2adj+pmax+slope*clip_bev2, len/2-clip_bev2],
1914                               [                    rmax+1, len/2-clip_bev2],
1915                               [                    rmax+1, len2+1],
1916                               [                         0, len2+1]]);
1917              if (!blunt_start1 && clip_bev1<=0)
1918                  down(len/2) cuboid([2*rmax+1,2*rmax+1, -len1+1], anchor=TOP);                     
1919              if (!blunt_start2 && clip_bev2<=0)
1920                  up(len/2) cuboid([2*rmax+1,2*rmax+1, len2+1], anchor=BOTTOM);
1921          }
1922
1923          // Add bevel for internal thread mask
1924          if (clip_bev1<0) 
1925              down(len/2+.001)cyl(l=-clip_bev1, r2=r1adj+profmin, r1=r1adj+profmin+slope*clip_bev1-clip_bev1,anchor=BOTTOM);
1926          if (clip_bev2<0) 
1927              up(len/2+.001)cyl(l=-clip_bev2, r1=r2adj+profmin, r2=r2adj+profmin+slope*clip_bev1-clip_bev2,anchor=TOP);
1928
1929          // Add teardrop profile
1930          if (teardrop!=false) {
1931              fact = is_num(teardrop) ? assert(teardrop>=0,"teardrop value cannot be negative")1-1/sqrt(2)+teardrop
1932                   : is_bool(teardrop) ? 1-1/sqrt(2)+0.05
1933                   : teardrop=="max" ? 1/sqrt(2)
1934                   : assert(false,"invalid teardrop value");
1935              dummy = assert(fact<=1/sqrt(2), "teardrop value too large");
1936              pdepth = pmax-profmin;              
1937              trap1 = back((r1adj+pmax)/sqrt(2),path3d(list_rotate(trapezoid(ang=45,w1 = (r1adj+pmax)*sqrt(2), h = (r1adj+pmax)*fact,anchor=FWD),1),-l/2));
1938              trap2 = back((r2adj+pmax)/sqrt(2),path3d(list_rotate(trapezoid(ang=45,w1 = (r2adj+pmax)*sqrt(2), h = (r2adj+pmax)*fact,anchor=FWD),1), l/2));
1939              yproj = [[1,0,0],[0,0,0],[0,0,1]];
1940              p1a=trap1[0]+unit([0,0,-l/2]-trap1[0])*pdepth*3/4;
1941              p1b=last(trap1)+unit([0,0,-l/2]-last(trap1))*pdepth*3/4;
1942              p2a=trap2[0]+unit([0,0,l/2]-trap2[0])*pdepth*3/4;
1943              p2b=last(trap2)+  unit([0,0,l/2]-last(trap2))*pdepth*3/4     ;
1944              cut1 = reverse([p1a, p1a*yproj, p1b*yproj, p1b]);
1945              cut2 = reverse([p2a, p2a*yproj, p2b*yproj, p2b]);
1946              vert = [
1947                      [each cut1, each trap1],
1948                      [each cut2, each trap2]
1949              ];
1950              vnf_polyhedron(vnf_vertex_array(vert,caps=true,col_wrap=true));
1951              //     Old code creates an internal teardrop which unfortunately doesn't print well
1952              //ang = min(45,opp_hyp_to_ang(rmax+profmin, rmax+pmax));
1953              //xrot(-90) teardrop(l=l, r1=r1adj+profmin, r2=r2adj+profmin, ang=ang, cap_h1=r1adj+pmax, cap_h2=r2adj+pmax);
1954          }
1955        }
1956        children();
1957    }
1958}
1959
1960
1961
1962// Module: generic_threaded_nut()
1963// Synopsis: Creates a generic threaded nut.
1964// SynTags: Geom
1965// Topics: Threading, Screws
1966// See Also: generic_threaded_rod()
1967// Usage:
1968//   generic_threaded_nut(nutwidth, id, h|height|thickness, pitch, profile, [$slop], ...) [ATTACHMENTS];
1969// Description:
1970//   Constructs a hexagonal or square nut for an generic threaded rod using a user-supplied thread profile.
1971//   See {{generic_threaded_rod()}} for details on the profile specification.  
1972// Arguments:
1973//   nutwidth = outer dimension of nut from flat to flat.
1974//   id = inner diameter of threaded hole, measured from bottom of threads
1975//   h / height / thickness = height/thickness of nut.
1976//   pitch = Thread spacing.
1977//   profile = Thread profile.
1978//   ---
1979//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1980//   left_handed = if true, create left-handed threads.  Default = false
1981//   starts = The number of lead starts.  Default = 1
1982//   id1 = inner diameter at the bottom
1983//   id2 = inner diameter at the top
1984//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1985//   bevel1 = if true, bevel the outside of the nut bottom.
1986//   bevel2 = if true, bevel the outside of the nut top. 
1987//   bevang = set the angle for the outside nut bevel.  Default: 30
1988//   ibevel = if true, bevel the inside (the hole).   Default: true
1989//   ibevel1 = if true bevel the inside, bottom end.
1990//   ibevel2 = if true bevel the inside, top end.
1991//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1992//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1993//   blunt_start2 = If true apply truncated blunt start threads top end.
1994//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1995//   end_len1 = Specify unthreaded length at the bottom
1996//   end_len2 = Specify unthreaded length at the top
1997//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1998//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1999//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
2000//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
2001//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
2002//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
2003//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
2004//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
2005//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
2006//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
2007//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
2008function generic_threaded_nut(
2009    nutwidth,
2010    id,
2011    h,
2012    pitch,
2013    profile,
2014    shape="hex",
2015    left_handed=false,
2016    starts=1,
2017    bevel,bevel1,bevel2,bevang=30,
2018    ibevel, ibevel1, ibevel2,
2019    id1,id2, height, thickness, 
2020    length, l,
2021    blunt_start, blunt_start1, blunt_start2,
2022    lead_in, lead_in1, lead_in2,
2023    lead_in_ang, lead_in_ang1, lead_in_ang2,
2024    end_len, end_len1, end_len2,
2025    lead_in_shape="default",
2026    anchor, spin, orient
2027) = no_function("generic_threaded_nut");
2028module generic_threaded_nut(
2029    nutwidth,
2030    id,
2031    h,
2032    pitch,
2033    profile,
2034    shape="hex",
2035    left_handed=false,
2036    starts=1,
2037    bevel,bevel1,bevel2,bevang=30,
2038    ibevel, ibevel1, ibevel2,
2039    id1,id2, height, thickness, 
2040    length, l,
2041    blunt_start, blunt_start1, blunt_start2,
2042    lead_in, lead_in1, lead_in2,
2043    lead_in_ang, lead_in_ang1, lead_in_ang2,
2044    end_len, end_len1, end_len2,
2045    lead_in_shape="default",
2046    anchor, spin, orient
2047) {
2048    
2049    extra = 0.01;
2050    id1 = first_defined([id1,id]);
2051    id2 = first_defined([id2,id]);
2052    h = one_defined([h,height,thickness,l,length],"h,height,thickness,l,length");
2053    dummyA = assert(is_num(pitch) && pitch>=0, "pitch must be a nonnegative number")
2054             assert(is_num(h) && h>0, "height/thickness must be a positive number")
2055             assert(in_list(shape,["square","hex"]), "shape must be \"hex\" or \"square\"")
2056             assert(all_positive([id1,id2]), "Inner diameter(s) of nut must be positive number(s)");
2057    slope = (id2-id1)/h;
2058    full_id1 = id1-slope*extra/2;
2059    full_id2 = id2+slope*extra/2;
2060    ibevel1 = first_defined([ibevel1,ibevel,true]);
2061    ibevel2 = first_defined([ibevel2,ibevel,true]);
2062    bevel1 = first_defined([bevel1,bevel,shape=="hex"?true:false]);
2063    bevel2 = first_defined([bevel2,bevel,shape=="hex"?true:false]);
2064    depth = -pitch*min(column(profile,1));
2065    IBEV=0.05;
2066    vnf = linear_sweep(hexagon(id=nutwidth), height=h, center=true);
2067    attachable(anchor,spin,orient, size=shape=="square" ? [nutwidth,nutwidth,h] : undef, vnf=shape=="hex" ? vnf : undef) {
2068        difference() {
2069            _nutshape(nutwidth,h, shape,bevel1,bevel2);
2070            if (pitch==0) 
2071               cyl(l=h+extra, d1=full_id1+4*get_slop(), d2=full_id2+4*get_slop(),
2072                   chamfer1=ibevel1?-IBEV*full_id1:undef,
2073                   chamfer2=ibevel2?-IBEV*full_id2:undef);
2074            else
2075               generic_threaded_rod(
2076                     d1=full_id1,d2=full_id2,
2077                     l=h+extra,
2078                     pitch=pitch,
2079                     profile=profile,
2080                     left_handed=left_handed,
2081                     starts=starts,
2082                     internal=true,
2083                     bevel1=ibevel1,bevel2=ibevel2,
2084                     blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
2085                     lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
2086                     lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
2087                     end_len=end_len, end_len1=end_len1, end_len2=end_len2
2088                );
2089        }
2090        children();
2091    }
2092}
2093
2094
2095module _nutshape(nutwidth, h, shape, bevel1, bevel2)
2096{
2097   bevel_d=0.9;
2098   intersection(){
2099       if (shape=="hex")
2100         cyl(d=nutwidth, circum=true, $fn=6, l=h, chamfer1=bevel1?0:nutwidth*.01, chamfer2=bevel2?0:nutwidth*.01);
2101       else
2102         cuboid([nutwidth,nutwidth,h],chamfer=nutwidth*.01, except=[if (bevel1) BOT, if(bevel2) TOP]);
2103       fn = quantup(segs(r=nutwidth/2),shape=="hex"?6:4);
2104       d = shape=="hex" ? 2*nutwidth/sqrt(3) : sqrt(2)*nutwidth;
2105       chamfsize = (d-nutwidth)/2/bevel_d;
2106       cyl(d=d*.99,h=h+.01,realign=true,circum=true,$fn=fn,chamfer1=bevel1?chamfsize:0,chamfer2=bevel2?chamfsize:0,chamfang=30);
2107   }
2108}
2109
2110
2111// Module: thread_helix()
2112// Synopsis: Creates a thread helix to add to a cylinder.
2113// SynTags: Geom
2114// Topics: Threading, Screws
2115// See Also: generic_threaded_rod()
2116// Usage:
2117//     thread_helix(d, pitch, turns=, [thread_depth=], [thread_angle=|flank_angle=], [profile=], [starts=], [internal=], ...) {ATTACHMENTS};
2118//     thread_helix(d1=,d2=, pitch=, turns=, [thread_depth=], [thread_angle=|flank_angle=], [profile=], [starts=], [internal=], ...) {ATTACHMENTS};
2119// Description:
2120//   Creates a right-handed helical thread with optional end tapering.  Unlike
2121//   {{generic_threaded_rod()}, this module just generates the thread, and you specify the total
2122//   angle of threading that you want, which makes it easy to put complete threads onto a longer
2123//   shaft.  It also optionally makes a finely divided taper at the thread ends.  However, it takes
2124//   2-3 times as long to render compared to {{generic_threaded_rod()}}.  This module was designed
2125//   to handle threads found in plastic and glass bottles.
2126//   .
2127//   You can specify a thread_depth and flank_angle, in which case you get a symmetric trapezoidal
2128//   thread, whose inner diameter (the base of the threads for external threading) is d (so the
2129//   total diameter will be d + thread_depth).  This differs from the threaded_rod modules, where
2130//   the specified diameter is the outer diameter.  Alternatively you can give a profile, following
2131//   the same rules as for general_threaded_rod.  The Y=0 point will align with the specified
2132//   diameter, and the profile should range in X from -1/2 to 1/2.  You cannot specify both the
2133//   profile and the thread_depth or flank_angle.
2134//   .
2135//   Unlike {{generic_threaded_rod()}, when internal=true this module generates the threads, not a thread mask.
2136//   The profile needs to be inverted to produce the proper thread form.  If you use the built-in trapezoidal
2137//   thread you get the inverted thread, designed so that the inner diameter is d.  If you supply a custom profile
2138//   you must invert it yourself to get internal threads.  With adequate clearance
2139//   this thread will mate with the thread that uses the same parameters but has internal=false.  Note that
2140//   unlike the threaded_rod modules, thread_helix does not adjust the diameter for faceting, nor does it
2141//   subtract any $slop for clearance.  
2142//   .
2143//   The lead_in options specify a lead-in section where the ends of the threads scale down to avoid a sharp face at the thread ends.
2144//   You can specify the length of this scaling directly with the lead_in parameters or as an angle using the lead_in_ang parameters.
2145//   If you give a positive value, the extrusion is lengthenend by the specified distance or angle; if you give a negative
2146//   value then the scaled end is included in the extrusion length specified by `turns`.  If the value is zero then no scaled ends
2147//   are produced.  The shape of the scaled ends can be controlled with the lead_in_shape parameter.  Supported options are "sqrt", "linear"
2148//   "smooth" and "cut".  Lead-in works on both internal and external threads.
2149// Figure(2D,Med,NoAxes):
2150//   pa_delta = tan(15)/4;
2151//      rr1 = -1/2;
2152//      z1 = 1/4-pa_delta;
2153//      z2 = 1/4+pa_delta;
2154//      profile = [
2155//                  [-z2, rr1],
2156//                  [-z1,  0],
2157//                  [ z1,  0],
2158//                  [ z2, rr1],
2159//                ];
2160//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
2161//      stroke(fullprofile,width=1);
2162//      dir = fullprofile[2]-fullprofile[3];
2163//      dir2 = fullprofile[5]-fullprofile[4];
2164//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
2165//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
2166//      color("red"){
2167//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
2168//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
2169//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
2170//       right(14)back(19)text("flank",size=4,halign="center");
2171//       right(14)back(14)text("angle",size=4,halign="center");
2172//      }
2173// Figure(2D,Med,NoAxes):
2174//   pa_delta = tan(15)/4;
2175//   rr1 = -1/2;
2176//   z1 = 1/4-pa_delta;
2177//   z2 = 1/4+pa_delta;
2178//   profile = [
2179//               [-z2, rr1],
2180//               [-z1,  0],
2181//               [ z1,  0],
2182//               [ z2, rr1],
2183//             ];
2184//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
2185//   stroke(fullprofile,width=1);
2186//   dir = fullprofile[2]-fullprofile[3];
2187//   dir2 = fullprofile[5]-fullprofile[4];
2188//   curve = arc(32,angle=[75,105],r=67.5);
2189//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
2190//   color("red"){
2191//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
2192//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
2193//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
2194//    back(10)text("thread",size=4,halign="center");
2195//    back(3)text("angle",size=4,halign="center");
2196//   }
2197// Arguments:
2198//   d = Base diameter of threads.  Default: 10
2199//   pitch = Distance between threads.  Default: 2
2200//   ---
2201//   turns = Number of revolutions to rotate thread around.
2202//   thread_depth = Depth of threads from top to bottom.
2203//   flank_angle = Angle of thread faces to plane perpendicular to screw.  Default: 15 degrees.
2204//   thread_angle = Angle between two thread faces.  
2205//   profile = If an asymmetrical thread profile is needed, it can be specified here.
2206//   starts = The number of thread starts.  Default: 1
2207//   left_handed = If true, thread has a left-handed winding.
2208//   internal = if true make internal threads.  The only effect this has is to change how the thread lead_in is constructed. When true, the lead-in section tapers towards the outside; when false, it tapers towards the inside.  Default: false
2209//   d1 = Bottom inside base diameter of threads.
2210//   d2 = Top inside base diameter of threads.
2211//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
2212//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
2213//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
2214//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
2215//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
2216//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
2217//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "sqrt"
2218//   lead_in_sample = Factor to increase sample rate in the lead-in section.  Default: 10
2219//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
2220//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
2221//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
2222// Example(2DMed): Typical Tooth Profile
2223//   pitch = 2;
2224//   depth = pitch * cos(30) * 5/8;
2225//   profile = [
2226//       [-6/16, 0           ],
2227//       [-1/16, depth/pitch ],
2228//       [ 1/16, depth/pitch ],
2229//       [ 6/16, 0           ],
2230//   ];
2231//   stroke(profile, width=0.02);
2232// Examples:
2233//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, $fn=72);
2234//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, lead_in=1, $fn=72);
2235//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, lead_in=2, internal=true, $fn=72);
2236//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, lead_in=1, $fn=36);
2237function thread_helix(
2238    d, pitch, thread_depth, flank_angle, turns,
2239    profile, starts=1, left_handed=false, internal=false,
2240    d1, d2, thread_angle, 
2241    lead_in_shape,
2242    lead_in, lead_in1, lead_in2,
2243    lead_in_ang, lead_in_ang1, lead_in_ang2,
2244    lead_in_sample=10,
2245    anchor, spin, orient
2246) = no_function("thread_helix");
2247module thread_helix(
2248    d, pitch, thread_depth, flank_angle, turns,
2249    profile, starts=1, left_handed=false, internal=false,
2250    d1, d2, thread_angle, 
2251    lead_in_shape,
2252    lead_in, lead_in1, lead_in2,
2253    lead_in_ang, lead_in_ang1, lead_in_ang2,
2254    lead_in_sample=10,
2255    anchor, spin, orient
2256) {
2257    dummy1=assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle")
2258           assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),
2259                  "Cannot give thread_depth or flank_angle with a profile")
2260           assert(all_positive([turns]), "The turns parameter must be a positive number")
2261           assert(all_positive(pitch), "pitch must be a positive number")
2262           assert(num_defined([flank_angle,thread_angle])<=1, "Cannot give both thread_angle and flank_angle")
2263           assert(is_def(profile) || is_def(thread_depth), "If profile is not given, must give thread depth");
2264    flank_angle = first_defined([flank_angle,u_mul(0.5,thread_angle),15]);
2265    h = pitch*starts*abs(turns);
2266    r1 = get_radius(d1=d1, d=d, dflt=10);
2267    r2 = get_radius(d1=d2, d=d, dflt=10);
2268    profile = is_def(profile) ? profile :
2269        let(
2270            tdp = thread_depth / pitch,
2271            dz = tdp * tan(flank_angle),
2272            cap = (1 - 2*dz)/2
2273        )
2274        assert(cap/2+dz<=0.5, "Invalid geometry: incompatible thread depth and thread_angle/flank_angle")
2275        internal?
2276          [
2277            [-cap/2-dz, tdp],
2278            [-cap/2,    0  ],
2279            [+cap/2,    0  ],
2280            [+cap/2+dz, tdp],
2281          ]
2282        :
2283          [
2284            [+cap/2+dz, 0  ],
2285            [+cap/2,    tdp],
2286            [-cap/2,    tdp],
2287            [-cap/2-dz, 0  ],
2288          ];
2289
2290    pline = mirror([-1,1],  p = profile * pitch);
2291    dir = left_handed? -1 : 1;
2292    attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
2293        union(){
2294        zrot_copies(n=starts)
2295            spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, internal=internal,
2296                         lead_in_shape=lead_in_shape,
2297                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2,
2298                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
2299                         lead_in_sample=lead_in_sample,anchor=CENTER);
2300        }
2301        children();
2302    }
2303}
2304
2305
2306
2307// Questions
2308//   Should nut modules take d1/d2 for tapered nuts?
2309//
2310// Need explanation of what exactly the diff is between threaded_rod and helix_threads.
2311//
2312// What about blunt_start for ball screws?
2313// Should default bevel be capped at 1mm or 2mm or something like that?  Including/especially inner bevel on nuts
2314
2315// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
2316